/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2021 3snic Technologies Co., Ltd */

#ifndef SSSNIC_IO_H
#define SSSNIC_IO_H

#include "sssnic_crm.h"
#include "sssnic_common.h"
#include "sssnic_wq.h"

#define SSSNIC_MAX_TX_QUEUE_DEPTH	65536
#define SSSNIC_MAX_RX_QUEUE_DEPTH	16384

#define SSSNIC_MIN_QUEUE_DEPTH		128

#define SSSNIC_SQ_WQEBB_SHIFT		4
#define SSSNIC_RQ_WQEBB_SHIFT		3

#define SSSNIC_SQ_WQEBB_SIZE		BIT(SSSNIC_SQ_WQEBB_SHIFT)
#define SSSNIC_CQE_SIZE_SHIFT		4

enum sssnic_rq_wqe_type {
	SSSNIC_COMPACT_RQ_WQE,
	SSSNIC_NORMAL_RQ_WQE,
	SSSNIC_EXTEND_RQ_WQE,
};

struct sssnic_io_queue {
	struct ssshw_wq wq;
	union {
		u8 wqe_type; /* for rq */
		u8 owner; /* for sq */
	};

	u16 q_id;
	u16 msix_entry_idx;

	u8 __iomem *db_addr;

	union {
		struct {
			void *cons_idx_addr;
		} tx;

		struct {
			u16 *pi_virt_addr;
			dma_addr_t pi_dma_addr;
		} rx;
	};
} ____cacheline_aligned;

struct sssnic_nic_db {
	u32 db_info;
	u32 pi_hi;
};

#ifdef static
#undef static
#define SSSHW_LLT_STATIC_DEF_SAVED
#endif



#define TX_MSS_DEFAULT 0x3E00
#define TX_MSS_MIN 0x50

#define SSSNIC_MAX_SQ_SGE 18

#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_SHIFT 0
#define RQ_CQE_OFFOLAD_TYPE_IP_TYPE_SHIFT 5
#define RQ_CQE_OFFOLAD_TYPE_ENC_L3_TYPE_SHIFT 7
#define RQ_CQE_OFFOLAD_TYPE_TUNNEL_PKT_FORMAT_SHIFT 8
#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_SHIFT 19
#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_SHIFT 21
#define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_SHIFT 24

#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK 0x1FU
#define RQ_CQE_OFFOLAD_TYPE_IP_TYPE_MASK 0x3U
#define RQ_CQE_OFFOLAD_TYPE_ENC_L3_TYPE_MASK 0x1U
#define RQ_CQE_OFFOLAD_TYPE_TUNNEL_PKT_FORMAT_MASK 0xFU
#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_MASK 0x3U
#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_MASK 0x1U
#define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_MASK 0xFFU

#define RQ_CQE_OFFOLAD_TYPE_GET(val, member) \
	(((val) >> RQ_CQE_OFFOLAD_TYPE_##member##_SHIFT) & \
	 RQ_CQE_OFFOLAD_TYPE_##member##_MASK)

#define SSSNIC_GET_RX_PKT_TYPE(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)
#define SSSNIC_GET_RX_IP_TYPE(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, IP_TYPE)
#define SSSNIC_GET_RX_ENC_L3_TYPE(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, ENC_L3_TYPE)
#define SSSNIC_GET_RX_TUNNEL_PKT_FORMAT(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, TUNNEL_PKT_FORMAT)

#define SSSNIC_GET_RX_PKT_UMBCAST(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_UMBCAST)

#define SSSNIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, VLAN_EN)

#define SSSNIC_GET_RSS_TYPES(offload_type) \
	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, RSS_TYPE)

#define RQ_CQE_SGE_VLAN_SHIFT 0
#define RQ_CQE_SGE_LEN_SHIFT 16

#define RQ_CQE_SGE_VLAN_MASK 0xFFFFU
#define RQ_CQE_SGE_LEN_MASK 0xFFFFU

#define RQ_CQE_SGE_GET(val, member) \
	(((val) >> RQ_CQE_SGE_##member##_SHIFT) & RQ_CQE_SGE_##member##_MASK)

#define SSSNIC_GET_RX_VLAN_TAG(vlan_len) RQ_CQE_SGE_GET(vlan_len, VLAN)

#define SSSNIC_GET_RX_PKT_LEN(vlan_len) RQ_CQE_SGE_GET(vlan_len, LEN)

#define RQ_CQE_STATUS_CSUM_ERR_SHIFT 0
#define RQ_CQE_STATUS_NUM_LRO_SHIFT 16
#define RQ_CQE_STATUS_LRO_PUSH_SHIFT 25
#define RQ_CQE_STATUS_LRO_ENTER_SHIFT 26
#define RQ_CQE_STATUS_LRO_INTR_SHIFT 27

#define RQ_CQE_STATUS_BP_EN_SHIFT 30
#define RQ_CQE_STATUS_RXDONE_SHIFT 31
#define RQ_CQE_STATUS_DECRY_PKT_SHIFT 29
#define RQ_CQE_STATUS_FLUSH_SHIFT 28

#define RQ_CQE_STATUS_CSUM_ERR_MASK 0xFFFFU
#define RQ_CQE_STATUS_NUM_LRO_MASK 0xFFU
#define RQ_CQE_STATUS_LRO_PUSH_MASK 0X1U
#define RQ_CQE_STATUS_LRO_ENTER_MASK 0X1U
#define RQ_CQE_STATUS_LRO_INTR_MASK 0X1U
#define RQ_CQE_STATUS_BP_EN_MASK 0X1U
#define RQ_CQE_STATUS_RXDONE_MASK 0x1U
#define RQ_CQE_STATUS_FLUSH_MASK 0x1U
#define RQ_CQE_STATUS_DECRY_PKT_MASK 0x1U

#define RQ_CQE_STATUS_GET(val, member) \
	(((val) >> RQ_CQE_STATUS_##member##_SHIFT) & \
	 RQ_CQE_STATUS_##member##_MASK)

#define SSSNIC_GET_RX_CSUM_ERR(status) RQ_CQE_STATUS_GET(status, CSUM_ERR)

#define SSSNIC_GET_RX_DONE(status) RQ_CQE_STATUS_GET(status, RXDONE)

#define SSSNIC_GET_RX_FLUSH(status) RQ_CQE_STATUS_GET(status, FLUSH)

#define SSSNIC_GET_RX_BP_EN(status) RQ_CQE_STATUS_GET(status, BP_EN)

#define SSSNIC_GET_RX_NUM_LRO(status) RQ_CQE_STATUS_GET(status, NUM_LRO)

#define SSSNIC_RX_IS_DECRY_PKT(status) RQ_CQE_STATUS_GET(status, DECRY_PKT)

#define RQ_CQE_SUPER_CQE_EN_SHIFT 0
#define RQ_CQE_PKT_NUM_SHIFT 1
#define RQ_CQE_PKT_LAST_LEN_SHIFT 6
#define RQ_CQE_PKT_FIRST_LEN_SHIFT 19

#define RQ_CQE_SUPER_CQE_EN_MASK 0x1
#define RQ_CQE_PKT_NUM_MASK 0x1FU
#define RQ_CQE_PKT_FIRST_LEN_MASK 0x1FFFU
#define RQ_CQE_PKT_LAST_LEN_MASK 0x1FFFU

#define RQ_CQE_PKT_NUM_GET(val, member) \
	(((val) >> RQ_CQE_PKT_##member##_SHIFT) & RQ_CQE_PKT_##member##_MASK)
#define SSSNIC_GET_RQ_CQE_PKT_NUM(pkt_info) RQ_CQE_PKT_NUM_GET(pkt_info, NUM)

#define RQ_CQE_SUPER_CQE_EN_GET(val, member) \
	(((val) >> RQ_CQE_##member##_SHIFT) & RQ_CQE_##member##_MASK)
#define SSSNIC_GET_SUPER_CQE_EN(pkt_info) \
	RQ_CQE_SUPER_CQE_EN_GET(pkt_info, SUPER_CQE_EN)

#define RQ_CQE_PKT_LEN_GET(val, member) \
	(((val) >> RQ_CQE_PKT_##member##_SHIFT) & RQ_CQE_PKT_##member##_MASK)

#define RQ_CQE_DECRY_INFO_DECRY_STATUS_SHIFT 8
#define RQ_CQE_DECRY_INFO_ESP_NEXT_HEAD_SHIFT 0

#define RQ_CQE_DECRY_INFO_DECRY_STATUS_MASK 0xFFU
#define RQ_CQE_DECRY_INFO_ESP_NEXT_HEAD_MASK 0xFFU

#define RQ_CQE_DECRY_INFO_GET(val, member) \
	(((val) >> RQ_CQE_DECRY_INFO_##member##_SHIFT) & \
	 RQ_CQE_DECRY_INFO_##member##_MASK)

#define SSSNIC_GET_DECRYPT_STATUS(decry_info) \
	RQ_CQE_DECRY_INFO_GET(decry_info, DECRY_STATUS)

#define SSSNIC_GET_ESP_NEXT_HEAD(decry_info) \
	RQ_CQE_DECRY_INFO_GET(decry_info, ESP_NEXT_HEAD)

struct sssnic_rq_cqe {
	u32 status;
	u32 vlan_len;

	u32 offload_type;
	u32 hash_val;
	u32 xid;
	u32 decrypt_info;
	u32 rsvd6;
	u32 pkt_info;
};

struct sssnic_sge_sect {
	struct ssshw_sge sge;
	u32 rsvd;
};

struct sssnic_rq_extend_wqe {
	struct sssnic_sge_sect buf_desc;
	struct sssnic_sge_sect cqe_sect;
};

struct sssnic_rq_normal_wqe {
	u32 buf_hi_addr;
	u32 buf_lo_addr;
	u32 cqe_hi_addr;
	u32 cqe_lo_addr;
};

struct sssnic_rq_wqe {
	union {
		struct sssnic_rq_normal_wqe normal_wqe;
		struct sssnic_rq_extend_wqe extend_wqe;
	};
};

struct sssnic_sq_wqe_desc {
	u32 ctrl_len;
	u32 queue_info;
	u32 hi_addr;
	u32 lo_addr;
};

/* Engine only pass first 12B TS field directly to uCode through metadata
 * vlan_offoad is used for hardware when vlan insert in tx
 */
struct sssnic_sq_task {
	u32 pkt_info0;
	u32 ip_identify;
	u32 pkt_info2; /* ipsec used as spi */
	u32 vlan_offload;
};

struct sssnic_sq_bufdesc {
	u32 len; /* 31-bits Length, L2NIC only use length[17:0] */
	u32 rsvd;
	u32 hi_addr;
	u32 lo_addr;
};

struct sssnic_sq_compact_wqe {
	struct sssnic_sq_wqe_desc wqe_desc;
};

struct sssnic_sq_extend_wqe {
	struct sssnic_sq_wqe_desc wqe_desc;
	struct sssnic_sq_task task;
	struct sssnic_sq_bufdesc buf_desc[0];
};

struct sssnic_sq_wqe {
	union {
		struct sssnic_sq_compact_wqe compact_wqe;
		struct sssnic_sq_extend_wqe extend_wqe;
	};
};

/* use section pointer for support non continuous wqe */
struct sssnic_sq_wqe_combo {
	struct sssnic_sq_wqe_desc *ctrl_bd0;
	struct sssnic_sq_task *task;
	struct sssnic_sq_bufdesc *bds_head;
	struct sssnic_sq_bufdesc *bds_sec2;
	u16 first_bds_num;
	u32 wqe_type;
	u32 task_type;
};

/* ************* SQ_CTRL ************** */
enum sq_wqe_data_format {
	SQ_NORMAL_WQE = 0,
};

enum sq_wqe_ec_type {
	SQ_WQE_COMPACT_TYPE = 0,
	SQ_WQE_EXTENDED_TYPE = 1,
};

enum sq_wqe_tasksect_len_type {
	SQ_WQE_TASKSECT_46BITS = 0,
	SQ_WQE_TASKSECT_16BYTES = 1,
};

#define SQ_CTRL_BD0_LEN_SHIFT 0
#define SQ_CTRL_RSVD_SHIFT 18
#define SQ_CTRL_BUFDESC_NUM_SHIFT 19
#define SQ_CTRL_TASKSECT_LEN_SHIFT 27
#define SQ_CTRL_DATA_FORMAT_SHIFT 28
#define SQ_CTRL_DIRECT_SHIFT 29
#define SQ_CTRL_EXTENDED_SHIFT 30
#define SQ_CTRL_OWNER_SHIFT 31

#define SQ_CTRL_BD0_LEN_MASK 0x3FFFFU
#define SQ_CTRL_RSVD_MASK 0x1U
#define SQ_CTRL_BUFDESC_NUM_MASK 0xFFU
#define SQ_CTRL_TASKSECT_LEN_MASK 0x1U
#define SQ_CTRL_DATA_FORMAT_MASK 0x1U
#define SQ_CTRL_DIRECT_MASK 0x1U
#define SQ_CTRL_EXTENDED_MASK 0x1U
#define SQ_CTRL_OWNER_MASK 0x1U

#define SQ_CTRL_SET(val, member) \
	(((u32)(val) & SQ_CTRL_##member##_MASK) << SQ_CTRL_##member##_SHIFT)

#define SQ_CTRL_GET(val, member) \
	(((val) >> SQ_CTRL_##member##_SHIFT) & SQ_CTRL_##member##_MASK)

#define SQ_CTRL_CLEAR(val, member) \
	((val) & (~(SQ_CTRL_##member##_MASK << SQ_CTRL_##member##_SHIFT)))

#define SQ_CTRL_QUEUE_INFO_PKT_TYPE_SHIFT 0
#define SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT 2
#define SQ_CTRL_QUEUE_INFO_UFO_SHIFT 10
#define SQ_CTRL_QUEUE_INFO_TSO_SHIFT 11
#define SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT 12
#define SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13
#define SQ_CTRL_QUEUE_INFO_SCTP_SHIFT 27
#define SQ_CTRL_QUEUE_INFO_UC_SHIFT 28
#define SQ_CTRL_QUEUE_INFO_PRI_SHIFT 29

#define SQ_CTRL_QUEUE_INFO_PKT_TYPE_MASK 0x3U
#define SQ_CTRL_QUEUE_INFO_PLDOFF_MASK 0xFFU
#define SQ_CTRL_QUEUE_INFO_UFO_MASK 0x1U
#define SQ_CTRL_QUEUE_INFO_TSO_MASK 0x1U
#define SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK 0x1U
#define SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFFU
#define SQ_CTRL_QUEUE_INFO_SCTP_MASK 0x1U
#define SQ_CTRL_QUEUE_INFO_UC_MASK 0x1U
#define SQ_CTRL_QUEUE_INFO_PRI_MASK 0x7U

#define SQ_CTRL_QUEUE_INFO_SET(val, member) \
	(((u32)(val) & SQ_CTRL_QUEUE_INFO_##member##_MASK) << \
	 SQ_CTRL_QUEUE_INFO_##member##_SHIFT)

#define SQ_CTRL_QUEUE_INFO_GET(val, member) \
	(((val) >> SQ_CTRL_QUEUE_INFO_##member##_SHIFT) & \
	 SQ_CTRL_QUEUE_INFO_##member##_MASK)

#define SQ_CTRL_QUEUE_INFO_CLEAR(val, member) \
	((val) & (~(SQ_CTRL_QUEUE_INFO_##member##_MASK << \
		    SQ_CTRL_QUEUE_INFO_##member##_SHIFT)))

#define SQ_TASK_INFO0_TUNNEL_FLAG_SHIFT 19
#define SQ_TASK_INFO0_ESP_NEXT_PROTO_SHIFT 22
#define SQ_TASK_INFO0_INNER_L4_EN_SHIFT 24
#define SQ_TASK_INFO0_INNER_L3_EN_SHIFT 25
#define SQ_TASK_INFO0_INNER_L4_PSEUDO_SHIFT 26
#define SQ_TASK_INFO0_OUT_L4_EN_SHIFT 27
#define SQ_TASK_INFO0_OUT_L3_EN_SHIFT 28
#define SQ_TASK_INFO0_OUT_L4_PSEUDO_SHIFT 29
#define SQ_TASK_INFO0_ESP_OFFLOAD_SHIFT 30
#define SQ_TASK_INFO0_IPSEC_PROTO_SHIFT 31

#define SQ_TASK_INFO0_TUNNEL_FLAG_MASK 0x1U
#define SQ_TASK_INFO0_ESP_NEXT_PROTO_MASK 0x3U
#define SQ_TASK_INFO0_INNER_L4_EN_MASK 0x1U
#define SQ_TASK_INFO0_INNER_L3_EN_MASK 0x1U
#define SQ_TASK_INFO0_INNER_L4_PSEUDO_MASK 0x1U
#define SQ_TASK_INFO0_OUT_L4_EN_MASK 0x1U
#define SQ_TASK_INFO0_OUT_L3_EN_MASK 0x1U
#define SQ_TASK_INFO0_OUT_L4_PSEUDO_MASK 0x1U
#define SQ_TASK_INFO0_ESP_OFFLOAD_MASK 0x1U
#define SQ_TASK_INFO0_IPSEC_PROTO_MASK 0x1U

#define SQ_TASK_INFO0_SET(val, member) \
	(((u32)(val) & SQ_TASK_INFO0_##member##_MASK) << \
	 SQ_TASK_INFO0_##member##_SHIFT)
#define SQ_TASK_INFO0_GET(val, member) \
	(((val) >> SQ_TASK_INFO0_##member##_SHIFT) & \
	 SQ_TASK_INFO0_##member##_MASK)

#define SQ_TASK_INFO1_SET(val, member) \
	(((val) & SQ_TASK_INFO1_##member##_MASK) << \
	 SQ_TASK_INFO1_##member##_SHIFT)
#define SQ_TASK_INFO1_GET(val, member) \
	(((val) >> SQ_TASK_INFO1_##member##_SHIFT) & \
	 SQ_TASK_INFO1_##member##_MASK)

#define SQ_TASK_INFO3_VLAN_TAG_SHIFT 0
#define SQ_TASK_INFO3_VLAN_TYPE_SHIFT 16
#define SQ_TASK_INFO3_VLAN_TAG_VALID_SHIFT 19

#define SQ_TASK_INFO3_VLAN_TAG_MASK 0xFFFFU
#define SQ_TASK_INFO3_VLAN_TYPE_MASK 0x7U
#define SQ_TASK_INFO3_VLAN_TAG_VALID_MASK 0x1U

#define SQ_TASK_INFO3_SET(val, member) \
	(((val) & SQ_TASK_INFO3_##member##_MASK) << \
	 SQ_TASK_INFO3_##member##_SHIFT)
#define SQ_TASK_INFO3_GET(val, member) \
	(((val) >> SQ_TASK_INFO3_##member##_SHIFT) & \
	 SQ_TASK_INFO3_##member##_MASK)

#ifdef static
#undef static
#define SSSHW_LLT_STATIC_DEF_SAVED
#endif

static inline u32 sssnic_get_pkt_len_for_super_cqe(const struct sssnic_rq_cqe *cqe,
						   bool last)
{
	u32 pkt_len = ssshw_cpu32(cqe->pkt_info);

	if (!last)
		return RQ_CQE_PKT_LEN_GET(pkt_len, FIRST_LEN);
	else
		return RQ_CQE_PKT_LEN_GET(pkt_len, LAST_LEN);
}

/* *
 * sssnic_set_vlan_tx_offload - set vlan offload info
 * @task: wqe task section
 * @vlan_tag: vlan tag
 * @vlan_type: 0--select TPID0 in IPSU, 1--select TPID0 in IPSU
 * 2--select TPID2 in IPSU, 3--select TPID3 in IPSU, 4--select TPID4 in IPSU
 */
static inline void sssnic_set_vlan_tx_offload(struct sssnic_sq_task *task,
					      u16 vlan_tag, u8 vlan_type)
{
	task->vlan_offload = SQ_TASK_INFO3_SET(vlan_tag, VLAN_TAG) |
			     SQ_TASK_INFO3_SET(vlan_type, VLAN_TYPE) |
			     SQ_TASK_INFO3_SET(1U, VLAN_TAG_VALID);
}

#ifdef SSSHW_LLT_STATIC_DEF_SAVED
#define static
#undef SSSHW_LLT_STATIC_DEF_SAVED
#endif

/* *
 * @brief sssnic_get_sq_free_wqebbs - get send queue free wqebb
 * @param sq: send queue
 * @retval : number of free wqebb
 */
static inline u16 sssnic_get_sq_free_wqebbs(struct sssnic_io_queue *sq)
{
	return ssshw_wq_free_wqebbs(&sq->wq);
}

/* *
 * @brief sssnic_update_sq_local_ci - update send queue local consumer index
 * @param sq: send queue
 * @param wqe_cnt: number of wqebb
 */
static inline void sssnic_update_sq_local_ci(struct sssnic_io_queue *sq,
					     u16 wqebb_cnt)
{
	ssshw_wq_put_wqebbs(&sq->wq, wqebb_cnt);
}

/* *
 * @brief sssnic_get_sq_local_ci - get send queue local consumer index
 * @param sq: send queue
 * @retval : local consumer index
 */
static inline u16 sssnic_get_sq_local_ci(const struct sssnic_io_queue *sq)
{
	return SSSHW_WQ_MASK_IDX(&sq->wq, sq->wq.cons_idx);
}

/* *
 * @brief sssnic_get_sq_local_pi - get send queue local producer index
 * @param sq: send queue
 * @retval : local producer index
 */
static inline u16 sssnic_get_sq_local_pi(const struct sssnic_io_queue *sq)
{
	return SSSHW_WQ_MASK_IDX(&sq->wq, sq->wq.prod_idx);
}

/* *
 * @brief sssnic_get_sq_hw_ci - get send queue hardware consumer index
 * @param sq: send queue
 * @retval : hardware consumer index
 */
static inline u16 sssnic_get_sq_hw_ci(const struct sssnic_io_queue *sq)
{
	return SSSHW_WQ_MASK_IDX(&sq->wq,
			   ssshw_cpu16(*(u16 *)sq->tx.cons_idx_addr));
}

/* *
 * @brief sssnic_get_sq_one_wqebb - get send queue wqe with single wqebb
 * @param sq: send queue
 * @param pi: return current pi
 * @retval : wqe base address
 */
static inline void *sssnic_get_sq_one_wqebb(struct sssnic_io_queue *sq, u16 *pi)
{
	return sssnic_wq_get_one_wqebb(&sq->wq, pi);
}

/* *
 * @brief sssnic_get_sq_multi_wqebb - get send queue wqe with multiple wqebbs
 * @param sq: send queue
 * @param wqebb_cnt: wqebb counter
 * @param pi: return current pi
 * @param second_part_wqebbs_addr: second part wqebbs base address
 * @param first_part_wqebbs_num: number wqebbs of first part
 * @retval : first part wqebbs base address
 */
static inline void *sssnic_get_sq_multi_wqebbs(struct sssnic_io_queue *sq,
					       u16 wqebb_cnt, u16 *pi,
					       void **second_part_wqebbs_addr,
					       u16 *first_part_wqebbs_num)
{
	return sssnic_wq_get_multi_wqebbs(&sq->wq, wqebb_cnt, pi,
					  second_part_wqebbs_addr,
					  first_part_wqebbs_num);
}

/* *
 * @brief sssnic_get_and_update_sq_owner - get and update send queue owner bit
 * @param sq: send queue
 * @param curr_pi: current pi
 * @param wqebb_cnt: wqebb counter
 * @retval : owner bit
 */
static inline u16 sssnic_get_and_update_sq_owner(struct sssnic_io_queue *sq,
						 u16 curr_pi, u16 wqebb_cnt)
{
	u16 owner = sq->owner;

	if (unlikely(curr_pi + wqebb_cnt >= sq->wq.q_depth))
		sq->owner = !sq->owner;

	return owner;
}

/* *
 * @brief sssnic_get_sq_wqe_with_owner - get send queue wqe with owner
 * @param sq: send queue
 * @param wqebb_cnt: wqebb counter
 * @param pi: return current pi
 * @param owner: return owner bit
 * @param second_part_wqebbs_addr: second part wqebbs base address
 * @param first_part_wqebbs_num: number wqebbs of first part
 * @retval : first part wqebbs base address
 */
static inline void *sssnic_get_sq_wqe_with_owner(struct sssnic_io_queue *sq,
						 u16 wqebb_cnt, u16 *pi,
						 u16 *owner,
						 void **second_part_wqebbs_addr,
						 u16 *first_part_wqebbs_num)
{
	void *wqe = sssnic_wq_get_multi_wqebbs(&sq->wq, wqebb_cnt, pi,
					       second_part_wqebbs_addr,
					       first_part_wqebbs_num);

	*owner = sq->owner;
	if (unlikely(*pi + wqebb_cnt >= sq->wq.q_depth))
		sq->owner = !sq->owner;

	return wqe;
}

/* *
 * @brief sssnic_rollback_sq_wqebbs - rollback send queue wqe
 * @param sq: send queue
 * @param wqebb_cnt: wqebb counter
 * @param owner: owner bit
 */
static inline void sssnic_rollback_sq_wqebbs(struct sssnic_io_queue *sq,
					     u16 wqebb_cnt, u16 owner)
{
	if (owner != sq->owner)
		sq->owner = owner;
	sq->wq.prod_idx -= wqebb_cnt;
}

/* *
 * @brief sssnic_rq_wqe_addr - get receive queue wqe address by queue index
 * @param rq: receive queue
 * @param idx: wq index
 * @retval: wqe base address
 */
static inline void *sssnic_rq_wqe_addr(struct sssnic_io_queue *rq, u16 idx)
{
	return sssnic_wq_wqebb_addr(&rq->wq, idx);
}

/* *
 * @brief sssnic_update_rq_hw_pi - update receive queue hardware pi
 * @param rq: receive queue
 * @param pi: pi
 */
static inline void sssnic_update_rq_hw_pi(struct sssnic_io_queue *rq, u16 pi)
{
	*rq->rx.pi_virt_addr = cpu_to_be16((pi & rq->wq.idx_mask) <<
					   rq->wqe_type);
}

/* *
 * @brief sssnic_update_rq_local_ci - update receive queue local consumer index
 * @param sq: receive queue
 * @param wqe_cnt: number of wqebb
 */
static inline void sssnic_update_rq_local_ci(struct sssnic_io_queue *rq,
					     u16 wqebb_cnt)
{
	ssshw_wq_put_wqebbs(&rq->wq, wqebb_cnt);
}

/* *
 * @brief sssnic_get_rq_local_ci - get receive queue local ci
 * @param rq: receive queue
 * @retval: receive queue local ci
 */
static inline u16 sssnic_get_rq_local_ci(const struct sssnic_io_queue *rq)
{
	return SSSHW_WQ_MASK_IDX(&rq->wq, rq->wq.cons_idx);
}

/* *
 * @brief sssnic_get_rq_local_pi - get receive queue local pi
 * @param rq: receive queue
 * @retval: receive queue local pi
 */
static inline u16 sssnic_get_rq_local_pi(const struct sssnic_io_queue *rq)
{
	return SSSHW_WQ_MASK_IDX(&rq->wq, rq->wq.prod_idx);
}

/* ******************** DB INFO ******************** */
#define DB_INFO_QID_SHIFT		0
#define DB_INFO_NON_FILTER_SHIFT	22
#define DB_INFO_CFLAG_SHIFT		23
#define DB_INFO_COS_SHIFT		24
#define DB_INFO_TYPE_SHIFT		27

#define DB_INFO_QID_MASK		0x1FFFU
#define DB_INFO_NON_FILTER_MASK		0x1U
#define DB_INFO_CFLAG_MASK		0x1U
#define DB_INFO_COS_MASK		0x7U
#define DB_INFO_TYPE_MASK		0x1FU
#define DB_INFO_SET(val, member)	\
		(((u32)(val) & DB_INFO_##member##_MASK) << \
		 DB_INFO_##member##_SHIFT)

#define DB_PI_LOW_MASK			0xFFU
#define DB_PI_HIGH_MASK			0xFFU
#define DB_PI_LOW(pi)			((pi) & DB_PI_LOW_MASK)
#define DB_PI_HI_SHIFT			8
#define DB_PI_HIGH(pi)		(((pi) >> DB_PI_HI_SHIFT) & DB_PI_HIGH_MASK)
#define DB_ADDR(queue, pi)	((u64 *)((queue)->db_addr) + DB_PI_LOW(pi))
#define SRC_TYPE			1

/* CFLAG_DATA_PATH */
#define SQ_CFLAG_DP			0
#define RQ_CFLAG_DP			1
/* *
 * @brief sssnic_write_db - write doorbell
 * @param queue: nic io queue
 * @param cos: cos index
 * @param cflag: 0--sq, 1--rq
 * @param pi: product index
 */
#ifndef __UEFI__
static inline void sssnic_write_db(struct sssnic_io_queue *queue, int cos,
				   u8 cflag, u16 pi)
{
	struct sssnic_nic_db db;

	db.db_info = DB_INFO_SET(SRC_TYPE, TYPE) | DB_INFO_SET(cflag, CFLAG) |
			DB_INFO_SET(cos, COS) | DB_INFO_SET(queue->q_id, QID);
	db.pi_hi = DB_PI_HIGH(pi);
	/* Data should be written to HW in Big Endian Format */
	db.db_info = ssshw_be32(db.db_info);
	db.pi_hi = ssshw_be32(db.pi_hi);

	wmb(); /* Write all before the doorbell */

	writeq(*((u64 *)&db), DB_ADDR(queue, pi));
}
#else
void sssnic_write_db(void *pcidev, struct sssnic_io_queue *queue, int cos,
		     u8 cflag, u16 pi);
#endif

#ifdef SSSHW_LLT_STATIC_DEF_SAVED
#define static
#undef SSSHW_LLT_STATIC_DEF_SAVED
#endif

struct sssnic_dyna_qp_params {
	u16	num_qps;
	u32	sq_depth;
	u32	rq_depth;

	struct sssnic_io_queue *sqs;
	struct sssnic_io_queue *rqs;
};

int sssnic_alloc_qps(void *hwdev, struct ssshw_irq_info *qps_msix_arry,
		     struct sssnic_dyna_qp_params *qp_params);
void sssnic_free_qps(void *hwdev, struct sssnic_dyna_qp_params *qp_params);
int sssnic_init_qps(void *hwdev, struct sssnic_dyna_qp_params *qp_params);
void sssnic_deinit_qps(void *hwdev, struct sssnic_dyna_qp_params *qp_params);
int sssnic_init_nicio_res(void *hwdev);
void sssnic_deinit_nicio_res(void *hwdev);
#endif
